package me.numark.fragments;

import android.content.ContentValues;
import android.database.Cursor;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.TextView;

import com.marshalchen.ultimaterecyclerview.UltimateViewAdapter;
import com.squareup.picasso.Picasso;

import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

import butterknife.Bind;
import butterknife.ButterKnife;
import me.numark.R;
import me.numark.activities.ChatActivity;
import me.numark.activities.ProfileActivity;
import me.numark.model.Message;
import me.numark.model.User;
import me.numark.net.BaseResponse;
import me.numark.net.NetworkConstants;
import me.numark.net.RequestServerTask;
import me.numark.providers.Numa;
import me.numark.utils.Global;
import me.numark.utils.HttpUtil;
import me.numark.utils.MessageUtils;
import me.numark.utils.Utils;
import me.numark.view.BaseViewHolder;
import me.numark.view.CheckKeyboardLinearLayout;
import me.numark.view.CircleImageView;

/**
 * Created by Evan on 15/8/9.
 */
public class ChatFragment extends BaseListFragment implements CheckKeyboardLinearLayout.OnKeyboardShownListener,
        LoaderManager.LoaderCallbacks<Cursor> {

    @Bind(R.id.check_keyboard)
    CheckKeyboardLinearLayout checkKeyboardLayout;

    @Bind(R.id.inputbar)
    FrameLayout inputbar;

    @Bind(R.id.input_edit)
    EditText inputEdit;

    @Bind(R.id.input_btn)
    Button inputButton;


    int uid;
    long did;
    public User chatter = null;
    public User me;
    boolean fullLoaded = false;

    ChatActivity parent;
    ChatAdapter mChatAdapter;

    public static ChatFragment newInstance(int uid, String pic, String nick, long did) {
        ChatFragment fragment = new ChatFragment();
        Bundle args = new Bundle();
        args.putInt(ChatActivity.EXTRA_USER_UID, uid);
        args.putString(ChatActivity.EXTRA_USER_AVATAR, pic);
        args.putString(ChatActivity.EXTRA_USER_NICK, nick);
        args.putLong(ChatActivity.EXTRA_DID, did);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String pic = null;
        String nick = null;
        if (getArguments() != null) {
            uid = getArguments().getInt(ChatActivity.EXTRA_USER_UID, 0);
            did = getArguments().getLong(ChatActivity.EXTRA_DID, 0);
            pic = getArguments().getString(ChatActivity.EXTRA_USER_AVATAR);
            nick = getArguments().getString(ChatActivity.EXTRA_USER_NICK);
        }
        me = Global.currentUser;
        if (!TextUtils.isEmpty(pic) && !TextUtils.isEmpty(nick)) {
            chatter = new User();
            chatter.uid = uid;
            chatter.pic = pic;
            chatter.nick = nick;
        }
        mChatAdapter = new ChatAdapter(this, null);
        mAdapter = mChatAdapter;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_chat, container, false);
    }

    @Override
    public void initUI(View view) {
        super.initUI(view);
        parent = (ChatActivity) getActivity();
        titleTextView.setText(R.string.chat_title);
        checkKeyboardLayout.setListener(this);
        inputbar.setVisibility(View.VISIBLE);
        inputButton.setOnClickListener(this);
        inputButton.setText(R.string.send);
        setHasMore(false);
        loadDialogInfo();
    }

    @Override
    public void refresh() {
        onRefresh();
    }

    @Override
    public void onRefresh() {
        super.onRefresh();
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                if (did > 0) {
                    long beforeId = Long.MAX_VALUE;
                    Cursor cursor = mChatAdapter.mCursor;
                    if (cursor == null)
                        return null;
                    if (cursor.getCount() > 0) {
                        cursor.moveToPosition(0);
                        beforeId = cursor.getLong(cursor.getColumnIndex("_id"));
                    }
                    loadMoreMessages(did, beforeId, chatter == null);
                }
                return null;
            }

            @Override
            protected void onPostExecute(Void aVoid) {
                super.onPostExecute(aVoid);
                endRefreshing();
            }
        }.execute();
    }

    @Override
    protected void addDataToList(BaseResponse response, boolean isNew) {

    }

    @Override
    public void onKeyboardShown() {
        scrollToBottom();
    }

    @Override
    public void onKeyboardHidden() {
    }


    protected void loadDialogInfo() {
        String where;
        if (did > 0) {
            where = "_id=" + did;
        } else {
            where = "uid=" + uid;
        }
        Cursor cursor = getActivity().getContentResolver().query(Numa.DialogColumns.CONTENT_URI, null, where, null, null);
        if (cursor.moveToFirst()) {
            did = cursor.getLong(cursor.getColumnIndex("_id"));
            fullLoaded = cursor.getInt(cursor.getColumnIndex("fullLoaded")) > 0;
            if (chatter == null) {
                chatter = new User();
                chatter.uid = cursor.getInt(cursor.getColumnIndex("uid"));
                chatter.pic = cursor.getString(cursor.getColumnIndex("pic"));
                chatter.nick = cursor.getString(cursor.getColumnIndex("nick"));
            }
        }
        Utils.closeQuietly(cursor);
        if (chatter != null) {
            afterLoadUserInfo();
        }
        getLoaderManager().restartLoader(ChatFragment.class.hashCode(), null, this);
        Global.currentChatUid = uid;
    }

    protected void afterLoadUserInfo() {
        if (chatter.nick != null)
        titleTextView.setText(chatter.nick);
        uid = chatter.uid;
        parent.uid = uid;
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return new CursorLoader(getActivity(), Numa.MessageColumns.CONTENT_URI, null, "did=" + did, null, "time asc");
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        mChatAdapter.swapCursor(cursor);
        if (cursor.getCount() == 0) {
            new AsyncTask<Void, Void, Void>() {
                @Override
                protected Void doInBackground(Void... params) {
                    loadMoreMessages(did, Long.MAX_VALUE, chatter == null);
                    return null;
                }

                @Override
                protected void onPostExecute(Void aVoid) {
                    super.onPostExecute(aVoid);
                    scrollToBottom();
                }
            }.execute();
        } else {
            scrollToBottom();
        }
    }

    private void scrollToBottom() {
        recyclerView.scrollVerticallyToPosition(mChatAdapter.getItemCount() - 1);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        mChatAdapter.swapCursor(null);
    }

    @Override
    public void onClick(View v) {
        super.onClick(v);
        switch (v.getId()) {
            case R.id.input_btn:
                sendMessage();
                break;
        }
    }

    public boolean loadMoreMessages(long did, long mid, boolean userInfo) {
        String url = String.format(NetworkConstants.MSG_MESSAGES_URL, Global.getCurrentUid(), did);
        Map<String, Object> body = new LinkedHashMap<>();
        body.put("before_mid", String.valueOf(mid));
        body.put("uid", String.valueOf(Global.currentChatUid));
        body.put("userinfo", userInfo ? "1" : "0");
        body.put("limit", "30");
        String result = HttpUtil.get(url, body);
        MessageResponse response = null;
        try {
            if (result != null)
                response = Global.getGson().fromJson(result, MessageResponse.class);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        if (response == null || !response.ret || response.data == null) {
            return false;
        }
        if (userInfo && response.user != null) {
            chatter = response.user;
            //afterLoadUserInfo();
            mHandler.sendEmptyMessage(97);
        }
        if (!fullLoaded && !response.has_more && did > 0) {
            ContentValues values = new ContentValues();
            values.put("fullLoaded", true);
            getActivity().getContentResolver().update(Numa.DialogColumns.CONTENT_URI, values, "_id=" + did, null);
        }
        MessageUtils.parseMessages(response.data, getActivity().getContentResolver());
        return !response.has_more;
    }

    private String getHash() {
        return Global.DeviceUniqueID + String.valueOf(System.currentTimeMillis() % 10000000);
    }

    void sendMessage() {
        String text = inputEdit.getText().toString().trim();
        if (text.length() == 0) {
            return;
        }
        String hash = getHash();
        final String url = String.format(NetworkConstants.MSG_SEND_URL, Global.getCurrentUid());
        final Map<String, Object> body = new LinkedHashMap<>();
        body.put("uid", String.valueOf(Global.getCurrentUid()));
        body.put("reply_uid", String.valueOf(uid));
        body.put("description", text);
        body.put("hash", hash);
        if (did > 0) {
            body.put("did", String.valueOf(did));
        }
        new RequestServerTask<SendResponse>(SendResponse.class, this, getString(R.string.sending)) {
            @Override
            protected String requestServer() {
                return HttpUtil.post(url, body);
            }

            @Override
            protected void onSuccess(SendResponse result) {
                inputEdit.setText("");
                if (result.data != null) {
                    MessageUtils.parseMessages(new Message[]{result.data}, getActivity().getContentResolver());
                }
                MessageUtils.asyncUpdateMsg(getActivity());
                if (did == 0) {
                    did = result.data.did;
                    recyclerView.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            mHandler.sendEmptyMessage(99);
                        }
                    }, 100);
                }
            }
        }
                .setDefaultErrMsg(R.string.send_msg_failed)
                .start();

    }

    private  Handler mHandler = new Handler(){
        @Override
        public void handleMessage(android.os.Message msg)
        {
            if(msg.what == 99)
            {
                loadDialogInfo();
            }
            if (msg.what == 97){
                afterLoadUserInfo();
            }
        }
    };

    public static class SendResponse extends BaseResponse {

        public Message data;
    }

    public static class MessageResponse extends BaseResponse {

        public Message[] data;

        public User user;
    }

    class ChatAdapter extends UltimateViewAdapter<ChatViewHolder> {

        Cursor mCursor;
        ChatFragment mParent;
        SparseIntArray timeFlagArr = new SparseIntArray();
        static final int timeWindow = 10 * 60;
        Date today, yesterday, year;

        public ChatAdapter(ChatFragment parent, Cursor cursor) {
            mCursor = cursor;
            mParent = parent;
            Date[] dates = Utils.getMarkDate();
            today = dates[0];
            yesterday = dates[1];
            year = dates[2];
        }

        public Cursor swapCursor(Cursor newCursor) {
            if (newCursor == mCursor) {
                return null;
            }
            Cursor oldCursor = mCursor;
            mCursor = newCursor;
            notifyDataSetChanged();
            return oldCursor;
        }

        @Override
        public ChatViewHolder getViewHolder(View view) {
            return new ChatViewHolder(view, null);
        }

        @Override
        public ChatViewHolder onCreateViewHolder(ViewGroup viewGroup) {
            return null;
        }

        @Override
        public int getAdapterItemCount() {
            if (mCursor == null)
                return 0;
            return mCursor.getCount();
        }

        @Override
        public long generateHeaderId(int i) {
            return 0;
        }

        @Override
        public void onBindViewHolder(ChatViewHolder holder, int position) {
            if (mCursor == null || mCursor.getCount() <= position)
                return;
            mCursor.moveToPosition(position);
            final User user;
            int uid = mCursor.getInt(mCursor.getColumnIndex("uid"));
            if (uid == me.uid)
                user = me;
            else
                user = chatter;
            Picasso.with(getActivity()).load(user.pic).into(holder.chatAvatar);
            holder.chatContent.setText(mCursor.getString(mCursor.getColumnIndex("text")));
            long mid = mCursor.getLong(mCursor.getColumnIndex("_id"));
            long time = mCursor.getLong(mCursor.getColumnIndex("time"));
            boolean shouldShowTime = shouldShowTime(Math.abs(mid), time, mCursor, position);
            if (shouldShowTime) {
                holder.chatTime.setVisibility(View.VISIBLE);
                String timeText = Utils.getTimeShowText(new Date(time), yesterday, today, year);
                holder.chatTime.setText(timeText);
            } else {
                holder.chatTime.setVisibility(View.GONE);
            }
            holder.chatAvatar.setTag(user);
            holder.chatAvatar.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    ProfileActivity.openProfile(getActivity(),user.uid);
                }
            });
        }

        boolean shouldShowTime(long id, long time, Cursor c, int position) {
            if (id > 0 && time > 0) {
                time = time / 1000 / timeWindow;
                time = time % Integer.MAX_VALUE;
                int timeInt = (int) time;
                int minId = timeFlagArr.get(timeInt);
                int idInt = (int) (id % Integer.MAX_VALUE);
                if (minId == 0) {
                    timeFlagArr.put(timeInt, idInt);
                    shouldShowTime(0, 0, c, position - 1);
                    minId = timeFlagArr.get(timeInt);
                    return minId == idInt;
                } else {
                    if (minId == idInt) {
                        return true;
                    } else {
                        return false;
                    }
                }
            } else {
                if (position < 0) {
                    return false;
                }
                c.moveToPosition(position);
                time = c.getLong(c.getColumnIndex("time"));
                id = c.getLong(c.getColumnIndex("_id"));
                time = time / 1000 / timeWindow;
                time = time % Integer.MAX_VALUE;
                int timeInt = (int) time;
                int minId = timeFlagArr.get(timeInt);
                int idInt = (int) (id % Integer.MAX_VALUE);
                if (minId == 0) {
                    return false;
                } else {
                    if (minId > idInt) {
                        timeFlagArr.put(timeInt, idInt);
                        shouldShowTime(0, 0, c, position - 1);
                        return true;
                    }
                }
            }
            return false;
        }

        @Override
        public RecyclerView.ViewHolder onCreateHeaderViewHolder(ViewGroup viewGroup) {
            return null;
        }

        @Override
        public void onBindHeaderViewHolder(RecyclerView.ViewHolder viewHolder, int i) {

        }

        @Override
        public int getItemViewType(int position) {
            int type = position == this.getItemCount() - 1 && this.customLoadMoreView != null ? (this.isLoadMoreChanged ? 3 : 2) : (position == 0 && this.customHeaderView != null ? 1 : 0);
            if (type == 0) {
                mCursor.moveToPosition(position);
                int uid = mCursor.getInt(mCursor.getColumnIndex("uid"));
                if (uid == me.uid)
                    return 0;
                else
                    return 4;
            }
            return type;
        }



        @Override
        public ChatViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if (viewType == 0) {
                View view = LayoutInflater.from(parent.getContext()).inflate(
                        R.layout.msg_right_content, parent, false);
                return new ChatViewHolder(view, mParent);
            } else if (viewType == 4) {
                View view = LayoutInflater.from(parent.getContext()).inflate(
                        R.layout.msg_left_content, parent, false);
                return new ChatViewHolder(view, mParent);
            }

            return super.onCreateViewHolder(parent, viewType);
        }
    }

    class ChatViewHolder extends BaseViewHolder {

        @Bind(R.id.chat_time)
        TextView chatTime;
        @Bind(R.id.chat_avatar)
        CircleImageView chatAvatar;
        @Bind(R.id.chat_content)
        TextView chatContent;

        public ChatViewHolder(View itemView, Object parent) {
            super(itemView, parent);
            if (parent == null)
                return;
            ButterKnife.bind(this, itemView);
            chatAvatar.setBorderWidth(2);
            chatAvatar.setBorderColor(Global.avatarColor);
            addOnClickListener(chatAvatar);
            chatAvatar.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
           /* switch (v.getId()){
                case R.id.avatar:
                    User user = (User)v.getTag();
                    if (user != null){

                    }
                    break;
            }*/

        }

    }
}
